<?php

namespace App\Service;


use App\Models\Admin;
use App\Models\User;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Crypt;
use App\Models\SiteMsg;
use Illuminate\Support\Facades\Config;

class Option
{

    // 设置传递参数信息
    // 主要参数：
    //       1、传递的 $request 参数，
    //       2、传递到模板页面的 $assign 参数，
    //       3、传递缓存的参数
    //       4、传递的响应参数
    //       5、token处理
    //       6、session与cookie的处理

    // 很多时候某些服务不能传递参数
    // 所以新建这么一个类，用于传递参数（先设置参数，然后在特定的地方使用这个参数）

    // 需要用的
    // 使用静态属性 方便多次实例化的时候，只有一次传值：其他时候实例化同样可以调用该属性的值
    protected static $options;
    protected static $app;
    protected static $request;
    protected static $data;
    protected static $whole;  // 整理过的所有数据，下次使用的时候直接调用，不在处理（主要包含传递的参数，header，token，cookie，请求的参数等）
    //protected static $myUser;  // 用户在控制器判断

    // 页面
    protected static $assign;
    // 5、token处理（主要用于在外部：如控制器与逻辑操作以及中间件生成缓存等）
    protected static $token;
    // 6、session与cookie的处理（主要用于在外部：如控制器与逻辑操作以及中间件生成缓存等）
    protected static $user;

    protected $error;
    protected $code;

    // 构造方法
    public function __construct() { }

    // 设置 request
    public function request()
    {
        return self::$request;
    }

    // 获取当前域名
    public function domain($type = 'full')
    {
        if(empty($type)){
            return false;
        }

        // 如果已经整理过的数据 则直接返回
        if(isset(self::$whole['request']['domain'][$type])){
            return self::$whole['request']['domain'][$type];
        }

        //echo $this->request->getHttpHost();  www.shop.com
        //echo $this->request->host();  www.shop.com
        //echo $this->request->getScheme();  http
        //echo $this->request->schemeAndHttpHost();  http://www.shop.com
        // 域名全写
        if($type == 'full'){
            $domain = self::$request->schemeAndHttpHost();
        } elseif($type == 'top'){
            // 顶级域名
            //$domain = self::$request->rootDomain();
        } elseif($type == 'old'){
            // 历史域名
            $domain = Config::get('app.old_host');
            if(empty($domain)){
                $domain = 'http://cdn.old.com/';
            }
        } elseif($type == 'static'){
            // 获取静态网站域名：用于储存样式表，js等静态信息的
            //  如果没有设置，则会保存在当前域名下
            $domain = Config::get('app.static_host');
            if(empty($domain)){
                $domain = self::$request->schemeAndHttpHost();
            }
        } elseif($type == 'oss'){
            // 获取对象储存域名：用于储存上传的图片地址的
            // 如果没有定于对象储存 则获取当前域名
            $domain = Config::get('app.oss_host');
            if(empty($domain)){
                $domain = self::$request->schemeAndHttpHost();
            }
        }
        if(empty($domain)){
            return false;
        }
        if(substr($domain, -1) != '/'){
            $domain = $domain.'/';
        }

        // 整理返回
        self::$whole['request']['domain'][$type] = $domain;

        return $domain;
    }

    // 替换域名（保存到数据库中和获取到页面显示改变数据中的域名地址）（用于修改器与获取器）
    public function replaceDomain($value, $to = 'full')
    {
        if(empty($value)){
            return $value;
        }

        // 替换
        $oldDomain = $this->domain('old');
        $nowDomain = $this->domain('oss');

        // full：展示
        if($to == 'full'){
            $value = str_replace($oldDomain, $nowDomain, $value);
        } else{
            // old：保存 保存为最原始的域名
            $value = str_replace($nowDomain, $oldDomain, $value);
        }

        return $value;
    }
    #######################################################################################################
    ## 设置数据
    // 设置app
    public function setApp($request)
    {
        if(empty(self::$request)){
            self::$request = $request;
        }
        if(empty(self::$data)){
            self::$data = array_merge($request->all(), $request->route()->parameters);
        }

        return $this;
    }

    // 设置参数
    public function setData($data)
    {
        self::$data = $data;

        return $this;
    }

    // 设置参数
    public function setUser($user)
    {
        self::$user = $user;

        return $this;
    }

    // 设置
    public function setToken($info, $type = 'admin')
    {
        // 组合
        $info['type']  = $type;
        $info['ctime'] = LARAVEL_TIME;
        // 制作Token
        $token = Crypt::encryptString(json_encode($info, JSON_UNESCAPED_UNICODE));

        return $token;
    }

    // 设置参数的值
    //   如果参数存在 则替换
    public function setField($field, $value = null)
    {
        if(empty(self::$data)){
            self::$data = [];
        }
        self::$data[$field] = $value;

        return $this;
    }

    // 改变参数的键名称
    // 设置新参数的值 并 删除以前的那个参数
    public function changeData($field, $to_field, $value = null)
    {
        if(empty(self::$data)){
            self::$data = [];
        }
        if(is_null($value)){
            $value = self::$data[$field] ?? null;
        }

        // 设置新参数的值 并 删除以前的那个参数
        self::$data[$to_field] = $value;
        unset(self::$data[$field]);

        return $this;
    }

    // 获取当前语言
    public function getLang()
    {
        // 确定语言
        //  如果指定语言，则保存 cookie
        //  如果没有指定语言，则或者 cookie，没有获取到则为英文
        $lang = self::$request->header('content-lang');
        $lang = $lang ?: $this->getData('web_lang', null, 'trim');
        if(!empty($lang)){
            Cookie::queue('web_language', $lang);
        } else{
            $lang = Cookie::get('web_language', 'en');
        }

        return $lang;
    }

    // 获取 翻译结果  从数据库中获取翻译结果
    public function translateDB($msg)
    {
        // 平时不使用翻译的时候 直接返回数据
        // return $msg;

        // 获取所有的数据
        $cache = true;
        $cache = false;
        $msgDb = new SiteMsg();
        $langs = $msgDb->getAllCache([]);
        $langs = array_column($langs, null, 'field');

        // 如果没有找到翻译 直接返回
        $info = $langs[$msg] ?? [];
        if(empty($info)){
            return str_replace('_', ' ', $msg).'.';
        }


        // 执行翻译
        $lang = $this->getLang();  // 确定语言
        if(($lang == 'cn') || ($lang == 'zh-cn') || ($lang == 'zh_cn')){
            $rst = $info['cn_msg'];
        } elseif($lang == 'tc'){
            $rst = $info['tc_msg'];
        } else{
            $rst = $info['en_msg'];
        }
        // 如果没有找到翻译 默认返回英文翻译
        if(empty($rst)){
            $rst = $info['en_msg'];
        }
        // 如果实在没有翻译 则直接返回
        if(empty($rst)){
            return str_replace('_', ' ', $msg).'.';
        }

        return $rst;
    }

    // 获取 翻译结果 使用自带的翻译：不能使用默认文件的翻译
    public function translate2($msg)
    {
        // 平时不使用翻译的时候 直接返回数据
        // return $msg;


        // 确定语言
        //  如果已经设置了语言，则不在设置语言
        $lang = App::getLocale();
        //  如果没有设置语言，则重新设置语言
        if(empty($lang)){
            $lang = $this->getLang();
            App::setLocale($lang);
        }

        $rst = trans($msg);

        return $rst;
    }

    // 获取 翻译结果  自己写的翻译
    public function translate($msg)
    {
        // 平时不使用翻译的时候 直接返回数据
        // return $msg;


        // 获取语言
        $lang = $this->getLang();
        if(($lang == 'cn') || ($lang == 'zh-cn') || ($lang == 'zh_cn')){
            $locale = 'zh';
        } elseif($lang == 'tc'){
            $locale = 'tc';
        } elseif($lang == 'en'){
            $locale = 'en';
        } else{
            $locale = 'en';
        }


        // 找到语言路径
        $path     = lang_path().DIRECTORY_SEPARATOR.$locale;
        $messages = explode('.', $msg);
        $_count   = count($messages);
        if($_count > 1){
            for($ii = 0; $ii < $_count - 1; $ii++){
                $path .= DIRECTORY_SEPARATOR.$messages[$ii];
            }
        }


        // 语言文件
        $langs = [];
        $file  = $path.'.php';
        if(file_exists($file)){
            $langs = include $file;
        }


        // 执行翻译
        $rst = $langs[$messages[$_count - 1]] ?? '';
        if(empty($rst)){
            return str_replace('_', ' ', $messages[$_count - 1]).'.';
        }

        return $rst;
    }
    #######################################################################################################
    ## 取得数据

    // 获取错误信息
    public function getError()
    {
        return $this->error;
    }

    // 获取错误编码
    public function getCode()
    {
        return $this->code;
    }

    // 获取当前ip
    public function getIp()
    {
        return self::$request->ip();
    }

    // $func 数据转换函数  如果为 true 则为 null 的时候也返回默认值
    public function getData($name = '', $def = null, $func = '')
    {
        $data = self::$data;

        if(empty($name)){
            return $data;
        }
        if(!isset($data[$name])){
            return $def;
        }
        // 如果已经整理过的数据 则直接返回
        if(isset(self::$whole['data'][$name])){
            return self::$whole['data'][$name];
        }
        /*if($data[$name]){
            if(empty($def)){
                return $data[$name];
            } else{
                return $def;
            }
        }*/
        // 传递为空字符串 接收为 null
        if(is_null($data[$name])){
            return $def;
        }

        // 特殊字段  已经存在了，直接返回
        if(($name == 'page') && (!empty($this->page))){
            return $this->page;
        } elseif(($name == 'rows') && (!empty($this->rows))){
            return $this->rows;
        }

        // 已经经过安全过滤操作 （过滤xss）
        $value = $data[$name];
        if(empty($func)){
            return $value;
        }

        // php 7种数据类型
        // 一般不是数组或对象的操作
        // 默认操作方法是  trim
        if(in_array($func, ['trim', 'intval'])){
            $this->throwReturn(is_object($value) || is_array($value), '参数错误，'.$name.'不能是数组或对象！');

            // 如果是默认方法 trim 同时又是传递的是数字 则不做任何处理
            //$this->throwReturn(is_numeric($value) && $func=='trim','参数错误，'.$name.'必须是字符串！');
            //if($func == 'trim' && is_numeric($value)){}
            $return = $value;
        } elseif(in_array($func, ['is_array', 'json_encode'])){
            $this->throwReturn(!is_array($value), '参数错误，'.$name.'必须是数组或对象');
            if($func == 'is_array'){
                $return = $value;
            } elseif($func == 'json_encode'){
                $return = $this->jsonChinese($value);
            }
        }

        // 整理返回
        if($name == 'page'){
            $return = $return < 1 ? 1 : $return;;
        }
        if(empty($return) && ($func != 'is_array')){
            $return = $func($value);
        }
        self::$whole['data'][$name] = $return;

        return $return;
    }

    // 获取Header中的参数值
    public function getHeader(string $key = '', $default = null)
    {
        // HTTP请求头信息的名称不区分大小写，并且 _ 会自动转换为 -
        $result = self::$request->header($key);
        if(empty($result)) return $default;

        return $result;
    }

    // 获取用户信息
    public function getUser(string $key = '')
    {
        $user = self::$user;
        if($key){
            return $user[$key] ?? null;
        }

        return $user;
    }

    #######################################################################################################
    // 制作翻页
    public function getPages($total, $page, $rows)
    {
        $result = (new App\Service\Page($total, $page, $rows))->show();

        return $result;
    }

    // 加载模板输出
    public function dispaly($template, $vars = [], $checkMobile = true)
    {
        $vars = empty($vars) ? self::$assign : (self::$assign ? array_merge(self::$assign, $vars) : $vars);
        $vars = empty($vars) ? [] : $vars;
        if($checkMobile){
            $tpl_file = ($this->isMobile() ? 'wap/' : 'pc/').$template;
        } else{
            $tpl_file = $template;
        }

        return view($tpl_file, $vars);
    }

    // 返回数据
    public function assign($name, $value = '')
    {
        if(is_array($name)){
            self::$assign = array_merge(self::$assign, $name);
        } else{
            self::$assign[$name] = $value;
        }

        return $this;
    }

    public function getAssign($name, $value = '')
    {
        return self::$assign[$name] ?? $value;
    }

    // 关键字查询
    // $where[] = $this->orWhere('title|describe', 'like', $keyword);
    public function orWhere($column, $type, $value)
    {
        // 失败 同where
        //$query->orWhere([['title', 'like', "%$keyword%"], ['describe', 'like', "%$keyword%"]]);
        // 成功
        //$query->orWhere('title', 'like', "%$keyword%")->orWhere('describe', 'like', "%$keyword%");

        $where = function($query) use ($column, $type, $value) {
            $columns = explode('|', $column);
            if($type == 'like'){
                $value = '%'.$value.'%';
            }
            foreach($columns as $_column){
                $query = $query->orWhere($_column, $type, $value);
            }
        };

        return [$where];
    }

    #######################################################################################################
    ## token、cookie、session等的处理
    // 获取用户以及权限
    public function token($tokenField = 'token')
    {
        $myUser = self::$token;
        if(!isset(self::$token)){
            $myUser = [];
            $token  = self::$request->header($tokenField);
            if(!empty($token)){
                // TODO 为了避免解析以前的token报错（The payload is invalid.）
                try{
                    $myUser = Crypt::decryptString($token);
                    $myUser = json_decode($myUser, true);
                } catch(\Exception $e){
                    $myUser = [];
                }
                if(empty($myUser)){
                    //return $this->_returnFail('token过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('token_expired_login_again', LOGIN_ERROR);
                }
                if(empty($myUser['ctime'])){
                    //return $this->_returnFail('token过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('token_expired_login_again', LOGIN_ERROR);
                }
                if(empty($myUser['type'])){
                    //return $this->_returnFail('token过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('token_expired_login_again', LOGIN_ERROR);
                }

                // 查看登录的用户信息
                if($myUser['type'] == 'user'){
                    $userDb = new User();
                } elseif($myUser['type'] == 'admin'){
                    $userDb = new Admin();
                }

                $info = $userDb->oneFindCache(['id' => $myUser['id']], ['id' => $myUser['id']]);
                //$this->throwIf(empty($info), '用户不存在！！');
                //$this->throwIf($info['verify'] === 0, '你暂未通过审核！！');
                if(empty($info)){
                    //return $this->_returnFail('登录过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('login_expired_login_again', LOGIN_ERROR);
                }
                if($info['status'] == -1){
                    //return $this->_returnFail('登录过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('login_expired_login_again', LOGIN_ERROR);
                }
                if($info['status'] < 0){
                    //return $this->_returnFail('登录过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('login_expired_login_again', LOGIN_ERROR);
                }
                if($info['status'] == 0){
                    //return $this->_returnFail('对不起，你已经被禁用！！', LOGIN_ERROR);
                    return $this->_returnFail('your_account_has_been_disabled', LOGIN_ERROR);
                }

                $myUser = is_object($info) ? $info->toArray() : $info;
                // 组合
                $myUser['uid'] = $myUser['id'];
            }

            self::$token = $myUser;
        }

        /*if(empty($field)){
            return $myUser;
        }

        return $myUser[$field] ?? null;*/

        return $myUser;
    }

    // cookie、session
    public function session($field = '')
    {
        $myUser = self::$user;
        if(!isset(self::$user)){
            $myUser = [];
            $uid    = self::$request->session()->get('uid');
            if(!empty($uid)){
                // 查看登录的用户信息
                $userDb = new User();
                $info   = $userDb->oneFindCache(['id' => $uid], ['id' => $uid]);
                if(empty($info)){
                    //return $this->_returnFail('登录过期，请重新登录！！', LOGIN_ERROR);
                    return $this->_returnFail('login_expired_login_again', LOGIN_ERROR);
                }
                if($info['verify'] === 0){
                    //return $this->_returnFail('你暂未通过审核！');
                }

                $myUser = is_object($info) ? $info->toArray() : $info;
                // 组合
                $myUser['uid'] = $myUser['id'];
            }

            self::$user = $myUser;
        }

        if(empty($field)){
            return $myUser;
        }

        return $myUser[$field] ?? null;
    }


    // 判断是否是手机端
    public function isMobile():bool
    {
        // 如果已经整理过的数据 则直接返回
        if(isset(self::$whole['request']['is_mobile'])){
            return self::$whole['request']['is_mobile'];
        }

        // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
        if(isset ($_SERVER['HTTP_X_WAP_PROFILE'])){
            $return = true;
        }

        // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
        if(empty($return) && isset ($_SERVER['HTTP_VIA'])){
            $return = stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;// 找不到为flase,否则为TRUE
        }

        // 判断手机发送的客户端标志,兼容性有待提高
        if(empty($return) && isset ($_SERVER['HTTP_USER_AGENT'])){
            $clientkeywords = array(
                'mobile',
                'nokia',
                'sony',
                'ericsson',
                'mot',
                'samsung',
                'htc',
                'sgh',
                'lg',
                'sharp',
                'sie-',
                'philips',
                'panasonic',
                'alcatel',
                'lenovo',
                'iphone',
                'ipod',
                'blackberry',
                'meizu',
                'android',
                'netfront',
                'symbian',
                'ucweb',
                'windowsce',
                'palm',
                'operamini',
                'operamobi',
                'openwave',
                'nexusone',
                'cldc',
                'midp',
                'wap',
            );
            // 从HTTP_USER_AGENT中查找手机浏览器的关键字
            if(preg_match("/(".implode('|', $clientkeywords).")/i", strtolower($_SERVER['HTTP_USER_AGENT']))){
                $return = true;
            }
        }

        if(empty($return) && isset ($_SERVER['HTTP_ACCEPT'])){ // 协议法，因为有可能不准确，放到最后判断
            // 如果只支持wml并且不支持html那一定是移动设备
            // 如果支持wml和html但是wml在html之前则是移动设备
            if((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))){
                $return = true;
            }
        }

        // 整理返回
        if(empty($return)){
            $return = false;
        }
        self::$whole['request']['is_mobile'] = $return;

        return $return;
    }

    #######################################################################################################
    ## 异常

    // 抛出异常
    public function throwReturn($condition, $msg, $code = 400)
    {
        if($condition){
            throw new \RuntimeException($msg, $code);
        }
    }

    // 抛出异常
    public function throwIf($condition, $msg, $code = 400)
    {
        if($condition){
            throw new \RuntimeException($msg, $code);
        }
    }

    // 在初始化中，不会抛出异常，只能使用终止程序
    public function dieIf($condition, $msg, $code = 400, $is_encode = IS_ENCODE)
    {
        if($condition){
            $json = ['msg' => $msg, 'code' => $code, 'data' => [],];
            if($is_encode){
                //$json = ['data' => $this->encode($data)];
            } else{
                $json['access'] = 1; //不加密
            }

            $json = json_encode($json);
            die($json);
        }
    }

    #######################################################################################################
    // 验证
    // 表单验证信息
    public function validator($data, $rules = [], $attr = [])
    {
        if(empty($rules)){
            return true;
        }

        // 消息
        $messages = [
            'required'  => ':attribute必须填写！',
            'integer'   => ':attribute必须为整数！',
            'same'      => ':attribute必须与:other相同！！',
            'not_in'    => '所选:attribute无效！',
            'not_regex' => ':attribute格式无效！',
            'numeric'   => ':attribute必须是数字！',
            'password'  => '密码不正确！',
            'image'     => ':attribute必须是图像！',
            'in'        => '选定的:attribute无效！',
            'in_array'  => ':attribute段不存在于:other！',
            'ip'        => ':attribute必须是有效的ip地址！',
            'ipv4'      => ':attribute必须是有效的ipv4地址！',
            'ipv6'      => ':attribute必须是有效的ipv6地址！',
            'json'      => ':attribute必须是有效的json字符串！',
            'unique'    => ':attribute字段已经在数据表中存在！',
            'present'   => ':attribute字段可以为空但必须存在！',

            'required_with'        => '当:values存在时，:attribute必填！',
            'required_with_all'    => '当:values都存在时，:attribute必填！',
            'required_without'     => '当:values不存在时，:attribute必填!',
            'required_without_all' => ':values和:attribute不能同时为空！',

            'size'    => [
                'numeric' => 'The :attribute must be :size！',
                'file'    => 'The :attribute must be :size kilobytes！',
                'string'  => 'The :attribute must be :size characters！',
                'array'   => 'The :attribute must contain :size items！',
            ],

            //'min'       => ':attribute最小长度为:min！',
            //'max'       => ':attribute最大长度为:max！',
            //'between'   => ':attribute长度在:min和:max之间！',
            'min'     => [
                'numeric' => ':attribute必须大于:min！',
                'file'    => ':attribute必须大于:min千字节！',
                'string'  => ':attribute必须长度大于:min！',
                'array'   => ':attribute元素必须大于:min！',
            ],
            'between' => [
                'numeric' => ':attribute必须在:min和:max！',
                'file'    => ':attribute必须在:min千字节和:max千字节之间！',
                'string'  => ':attribute长度必须在:min和:max之间！',
                'array'   => ':attribute元素个数必须在:min和:max之间！',
            ],
            'max'     => [
                'numeric' => ':attribute必须小于:max！',
                'file'    => ':attribute必须小于:max千字节！',
                'string'  => ':attribute长度必须小于:max！',
                'array'   => ':attribute元素个数必须小于:max！',
            ],
            'gt'      => [
                'numeric' => ':attribute必须大于:value！',
                'file'    => ':attribute必须大于:value千字节！',
                'string'  => ':attribute必须大于:value字符数！',
                'array'   => ':attribute必须多于:value个元素！',
            ],
            'gte'     => [
                'numeric' => ':attribute必须大于或等于:value！',
                'file'    => ':attribute必须大于或等于:value千字节！',
                'string'  => ':attribute必须大于或等于:value字符数！',
                'array'   => ':attribute元素个数必须等于或多于:value！',
            ],

            'lt'  => [
                'numeric' => ':attribute必须小于:value！',
                'file'    => ':attribute必须小于:value千字节！',
                'string'  => ':attribute必须小于:value字符数！',
                'array'   => ':attribute元素个数必须小于:value！',
            ],
            'lte' => [
                'numeric' => ':attribute必须小于或等于:value！',
                'file'    => ':attribute必须小于或等于:value千字节！',
                'string'  => ':attribute必须小于或等于:value字符数！',
                'array'   => ':attribute元素个数必须小于或等于:value！',
            ],
            //'sometimes' => '',

            'accepted'        => 'The :attribute must be accepted！',
            'active_url'      => 'The :attribute is not a valid URL！',
            'after'           => 'The :attribute must be a date after :date！',
            'after_or_equal'  => 'The :attribute must be a date after or equal to :date！',
            'alpha'           => 'The :attribute may only contain letters！',
            'alpha_dash'      => 'The :attribute may only contain letters, numbers, dashes and underscores！',
            'alpha_num'       => 'The :attribute may only contain letters and numbers！',
            'array'           => 'The :attribute must be an array！',
            'before'          => 'The :attribute must be a date before :date！',
            'before_or_equal' => 'The :attribute must be a date before or equal to :date！',
            'boolean'         => 'The :attribute field must be true or false！',
            'confirmed'       => 'The :attribute confirmation does not match！',
            'date'            => 'The :attribute is not a valid date！',
            'date_equals'     => 'The :attribute must be a date equal to :date！',
            'date_format'     => 'The :attribute does not match the format :format！',
            'different'       => 'The :attribute and :other must be different！',
            'digits'          => 'The :attribute must be :digits digits！',
            'digits_between'  => 'The :attribute must be between :min and :max digits！',
            'dimensions'      => 'The :attribute has invalid image dimensions！',
            'distinct'        => 'The :attribute field has a duplicate value！',
            'email'           => 'The :attribute must be a valid email address！',
            'ends_with'       => 'The :attribute must end with one of the following: :values！',
            'exists'          => 'The selected :attribute is invalid！',
            'file'            => 'The :attribute must be a file！',
            'filled'          => 'The :attribute field must have a value！',


            'mimes'       => 'The :attribute must be a file of type: :values！',
            'mimetypes'   => 'The :attribute must be a file of type: :values！',
            'multiple_of' => 'The :attribute must be a multiple of :value',


            'regex'           => 'The :attribute format is invalid！',
            'required_if'     => '当:other值为:value时:attribute必传！',
            'required_unless' => 'The :attribute field is required unless :other is in :values！',
            'starts_with'     => 'The :attribute must start with one of the following: :values！',
            'string'          => 'The :attribute must be a string！',
            'timezone'        => 'The :attribute must be a valid zone！',
            'uploaded'        => 'The :attribute failed to upload！',
            'url'             => 'The :attribute format is invalid！',
            'uuid'            => 'The :attribute must be a valid UUID！',
        ];

        // 字段属性
        $attributes = [
            'nickname'          => '姓名',
            'username'          => '用户名',
            'password'          => '登录密码',
            'role'              => '角色',
            'article_no'        => '文章数量',
            'salt'              => '撒盐码',
            'status'            => '用户状态 1-正常 0-禁用',
            'ctime'             => '创建时间',
            'space'             => '广告位',
            'cate_id'           => '栏目ID',
            'image'             => '图片',
            'src'               => '链接',
            'describe'          => '话题描述',
            'author_id'         => '作家ID',
            'title'             => '标题',
            'channel'           => '栏目频道',
            'cover'             => '封面',
            'is_original'       => '是否原创 1-是 0-否',
            'original'          => '来源',
            'video_url'         => '视频链接',
            'duration'          => '音视频时长',
            'read_no'           => '浏览数',
            'virtual_no'        => '虚拟浏览数',
            'comment_no'        => '评论数量',
            'is_top'            => '首页推荐',
            'is_top_cate'       => '栏目页推荐',
            'is_comment'        => '评论权限',
            'is_major'          => '重磅',
            'article_id'        => '文章ID',
            'date'              => '时间',
            'day'               => '日',
            'month'             => '月份',
            'favorite_no'       => '收藏数量',
            'praise_no'         => '点赞数',
            'stamp_no'          => '踩踏数量',
            'share_no'          => '分享数量',
            'read_pc'           => 'pc浏览数',
            'read_ios'          => 'ios浏览数',
            'read_android'      => '安卓浏览数',
            'read_h5'           => 'h5浏览数',
            'virtual_pc'        => 'pc虚拟浏览数',
            'virtual_ios'       => 'iOS虚拟浏览数',
            'virtual_android'   => '安卓虚拟浏览数',
            'virtual_h5'        => 'h5虚拟浏览数',
            'unlock_no'         => '解锁数',
            'uid'               => '',
            'pid'               => '父级',
            'reply_no'          => '回复数量',
            'content'           => '内容',
            'praise'            => '点赞',
            'operate'           => '操作',
            'topic_id'          => '话题ID',
            'ip'                => '用户IP',
            'name'              => '栏目中文名称',
            'avatar'            => '头像',
            'signature'         => '个性签名',
            'en_name'           => '英文名',
            'rank'              => '排序',
            'field'             => '字段',
            'cn_name'           => '中文名',
            'cn_value'          => '中文值',
            'en_value'          => '英文值',
            'keyword'           => '热门词',
            'language'          => '语言类型（1-中文，2-英文）',
            'follow_no'         => '关注人数',
            'virtual_follow_no' => '虚拟关注人数',
            'tag'               => '话题标签',
            'is_propose'        => '是否推荐',
            'residence'         => '居住地',
            'mail_address'      => '邮寄地址',
            'postal'            => '邮编',
            'birthday'          => '生日',
            'edu'               => '教育程度',
            'income'            => '月收入',
            'industry'          => '所处行业',
            'work_scope'        => '工作范畴',
            'company_type'      => '公司类型',
            'worker_no'         => '雇佣人数',
            'mtime'             => '更新时间',
            'email'             => '邮箱',
            'mobile'            => '手机号码 ',
            'head_img'          => '头像',
            'sex'               => '性别 1-男 2-女 0-保密',
            'surname'           => '姓',
            'realname'          => '名字',
            'facebook'          => '脸书openid',
            'twitter'           => '推特ID',
            'last_time'         => '最后登录时间',
            'last_ip'           => '最后登录IP',
        ];

        // 验证
        $attr      = array_merge($attributes, $attr);
        $validator = \Validator::make($data, $rules, $messages, $attr);
        if($validator->fails()){
            $messages    = $validator->errors();
            $this->error = $messages->first();

            return false;
        }

        return true;
    }

    // 删除空
    public function filterNull($data)
    {
        $after = [];
        foreach($data as $key => $row){
            if(is_null($row)){
                continue;
            }
            $after[$key] = $row;
        }

        return $after;
    }

    // 转化json,中文不转化
    public function jsonChinese(array $data = [])
    {
        return json_encode($data, JSON_UNESCAPED_UNICODE);
    }

    // 返回错误
    protected function _returnFail($error, $code = 400)
    {
        $this->error = $error;
        $this->code  = $code;

        return false;
    }

}
